package edu.isistan.matching.utils.serviceMatching;

import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.apache.log4j.Logger;

import edu.isistan.matching.IMatchingAlgorithm;
import edu.isistan.matching.filters.io.MatchingMap;
import edu.isistan.matching.scoreTypes.ComposeMatchScore;
import edu.isistan.matching.scoreTypes.MatchScore;
import edu.isistan.matching.scoreTypes.ScoreMatrix;
import edu.isistan.matching.structures.elements.PartElement;
import edu.isistan.matching.structures.elements.TypeElement;
import edu.isistan.metamodel.Composed;
import edu.isistan.metamodel.DataType;
import edu.isistan.metamodel.Interface;
import edu.isistan.metamodel.ModelElement;
import edu.isistan.metamodel.Operation;

public abstract class ServiceSimilarity implements IMatchingAlgorithm {

	protected static double MAXSCORE = 10;

	protected static double MEDIUM_SCORE = MAXSCORE / 2;

	protected static double MINSCORE = 0;
	
	static Logger logger = Logger.getLogger(ServiceSimilarity.class.getPackage().getName());

	public ServiceSimilarity() {
		
	}
	
	protected abstract MatchScore matchDataTypes(List<DataType> dataTypes0, List<DataType> dataTypes1);

	protected abstract MatchScore matchMessages(List<DataType> msg0, List<DataType> msg1);

	protected abstract MatchScore matchOperations(Operation op0, Operation op1);

	protected abstract MatchingMap matchInterfaces(Interface inf0, Interface inf1);

	public MatchingMap compareInterfaces(Interface inf0, Interface inf1) {
		return matchInterfaces(inf0, inf1);
	}

	protected boolean bothArePrimite(DataType type0, DataType type1) {
		return type0.isPrimitive() && type1.isPrimitive();  
	}

	protected boolean bothArePrimiteOrWrapper(DataType type0, DataType type1) {
		return (!type0.isCompoused() && !type1.isCompoused());  
	}
	
	protected boolean bothShareSameNameAndNamespace(TypeElement type0, TypeElement type1) {
		boolean retorno = (type0.getName() != null && type1.getName() != null && type0.getNameSpace() != null && type1.getNameSpace() != null);
		return retorno && type0.getName().equals(type1.getName()) && type0.getNameSpace().equals(type1.getNameSpace());
	}

	protected boolean someoneIsComplex(DataType type0, DataType type1) {
		return type0.isCompoused() || type1.isCompoused();
	}

	protected double matchIdenticalTypes(TypeElement type0, TypeElement type1) {
		getLogger().debug("MATCH IDENTICAL TYPES");
		getLogger().debug(type0.getType() + "==" + type1.getType());
		return MAXSCORE;
	}

	protected List<DataType> getCompositeDataElements(DataType type) {		
		List<DataType> r = new Vector<DataType>();
		if (type.isCompoused()) {
			r = ((Composed)type).getDataTypes();
		} else 
			r.add(type);
		return r;
	}

	protected double organizationBonus(DataType type1, DataType type2) {
		boolean sameOrganization = false;		
		if (sameOrganization) {
			return MAXSCORE;
		} else {
			return MINSCORE;
		}
	}

	protected List<TypeElement> getDataTypesAssociated(List<PartElement> parts) {
		List<TypeElement> wsdlTypes = new Vector<TypeElement>();
		Iterator<PartElement> itParts = parts.iterator();
		while (itParts.hasNext()) {
			PartElement part = itParts.next();
			wsdlTypes.add(part.getType());
		}
		return wsdlTypes;
	}

	// /METODOS PARA IMPRIMIR MATRICES
	protected void retrieveWSDLElementsPairs(ComposeMatchScore resultado, List wsdlParts1, List wsdlParts2) {
		ScoreMatrix scoreMatrix = resultado.getChildScoreMatrix();
		ModelElement[][] pairElements = new ModelElement[scoreMatrix.getMappingValues().length][2];
		for (int i = 0; i < scoreMatrix.getMappingValues().length; i++) {
			int valor1 = scoreMatrix.getMappingValues()[i][0];
			int valor2 = scoreMatrix.getMappingValues()[i][1];
			ModelElement element1 = (ModelElement) wsdlParts1.get(valor1);
			ModelElement element2 = (ModelElement) wsdlParts2.get(valor2);
			pairElements[i][0] = element1;
			pairElements[i][1] = element2;
		}
		resultado.getChildScoreMatrix().setMappingElements(pairElements);
	}

	protected void printMatrix(double[][] matrix, int m, int n, String message) {
		getLogger().debug(message);
		for (int i = 0; i < m; i++) {
			String row = "";
			for (int j = 0; j < n; j++) {
				row+="[" + matrix[i][j] + "]";
			}
			getLogger().debug(row);
		}
	}

	protected void printMatrix(Object[][] matrix, int m, int n, String message) {
		getLogger().debug(message);
		for (int i = 0; i < m; i++) {
			String row = "";
			for (int j = 0; j < n; j++) {
				row+="[" + matrix[i][j] + "]";
			}
			getLogger().debug(row);
		}
	}

	protected void printMatrix(int[][] matrix, int m, int n, String message) {
		getLogger().debug(message);
		for (int i = 0; i < m; i++) {
			String row = "";
			for (int j = 0; j < n; j++) {
				row+="[" + matrix[i][j] + "]";
			}
			getLogger().debug(row);
		}
	}

	
	public static Logger getLogger() {
		return logger;
	}
}